/**
 * 分块读文件
 * @param file string|buffer|int 路径 或 文件描述符
 * @param back function 分块回调  back(buffer)
 * @param opt json|null 选项
 * 		len: int|null 分块大小(B)  默认:64*1024->64K
 * 		ign: boolean 不存在是否忽略异常 默认false:抛出
 * 		syn: boolean 是否同步操作  默认false:异步
 * @return Promise|boolean 是否存在文件(opt.ign)
 */
$.fsPart = function(file, back, opt=null){
	opt=$.mix({len:65536,ign:false,syn:false},opt);
	let fd = typeof file==='number' ? file : null;
	const $FS=require('node:fs'), LEN=opt.len;
	if(opt.syn){
		if(!(fd=fd??$.fsOpen(file,opt))){
			if(opt.ign) return false;
			$.err('$.fsPart','EEXIST: '+file);
		}
		while(true){
			let buf = Buffer.allocUnsafe(LEN);
			let n = $FS.readSync(fd,buf,0,LEN);
			if(!n) return true; // 已读取完
			back(n===LEN?buf:buf.subarray(0,n));
		}
	}
	const w = $.track(()=>{
		const [W,Y,N]=$.when(), X={fd,highWaterMark:LEN};
		const readStream = $FS.createReadStream(file, X);
		readStream.on('data',back).on('end',()=>Y(true));
		readStream.on('error', e=>{
			console.log(222, e);
			if(!opt.ign) return N(e);  let x=e.code;
			x = 'ENOENT' || x==='ENXIO' || x==='ENOTDIR';
			if(x) Y(false); else N(e);
		});
		return W;
	});
	return w().catch(err=>$.err('$.fsPart',err));
};
